/******************************************************************************
 * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************/
#include "uart.h"

/**********************************************************************************************************************
 *                                			  local constants                                                       *
 *********************************************************************************************************************/

/**********************************************************************************************************************
 *                                           	local macro                                                        *
 *********************************************************************************************************************/

/**********************************************************************************************************************
 *                                             local data type                                                     *
 *********************************************************************************************************************/

/**********************************************************************************************************************
 *                                              global variable                                                       *
 *********************************************************************************************************************/
dma_config_t uart_tx_dma_config[2] = {{
                                          .dst_req_sel = DMA_REQ_UART0_TX,    // tx req
                                          .src_req_sel = 0,
                                          .dst_addr_ctrl = DMA_ADDR_FIX,
                                          .src_addr_ctrl = DMA_ADDR_INCREMENT,    // increment
                                          .dstmode = DMA_HANDSHAKE_MODE,          // handshake
                                          .srcmode = DMA_NORMAL_MODE,
                                          .dstwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .srcwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .src_burst_size = 0,               // must be 0
                                          .read_num_en = 0,
                                          .priority = 0,
                                          .write_num_en = 0,
                                          .auto_en = 0,    // must be 0
                                      },
                                      {
                                          .dst_req_sel = DMA_REQ_UART1_TX,    // tx req
                                          .src_req_sel = 0,
                                          .dst_addr_ctrl = DMA_ADDR_FIX,
                                          .src_addr_ctrl = DMA_ADDR_INCREMENT,    // increment
                                          .dstmode = DMA_HANDSHAKE_MODE,          // handshake
                                          .srcmode = DMA_NORMAL_MODE,
                                          .dstwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .srcwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .src_burst_size = 0,               // must be 0
                                          .read_num_en = 0,
                                          .priority = 0,
                                          .write_num_en = 0,
                                          .auto_en = 0,    // must be 0
                                      }};
dma_config_t uart_rx_dma_config[2] = {{
                                          .dst_req_sel = 0,    // tx req
                                          .src_req_sel = DMA_REQ_UART0_RX,
                                          .dst_addr_ctrl = DMA_ADDR_INCREMENT,
                                          .src_addr_ctrl = DMA_ADDR_FIX,
                                          .dstmode = DMA_NORMAL_MODE,
                                          .srcmode = DMA_HANDSHAKE_MODE,
                                          .dstwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .srcwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .src_burst_size = 0,
                                          .read_num_en = 0,
                                          .priority = 0,
                                          .write_num_en = 0,
                                          .auto_en = 0,    // must be 0
                                      },
                                      {
                                          .dst_req_sel = 0,    // tx req
                                          .src_req_sel = DMA_REQ_UART1_RX,
                                          .dst_addr_ctrl = DMA_ADDR_INCREMENT,
                                          .src_addr_ctrl = DMA_ADDR_FIX,
                                          .dstmode = DMA_NORMAL_MODE,
                                          .srcmode = DMA_HANDSHAKE_MODE,
                                          .dstwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .srcwidth = DMA_CTR_WORD_WIDTH,    // must be word
                                          .src_burst_size = 0,
                                          .read_num_en = 0,
                                          .priority = 0,
                                          .write_num_en = 0,
                                          .auto_en = 0,    // must be 0
                                      }};
/**********************************************************************************************************************
 *                                              local variable                                                     *
 *********************************************************************************************************************/
static unsigned char uart_dma_tx_chn[2];
static unsigned char uart_dma_rx_chn[2];
/**********************************************************************************************************************
 *                                          local function prototype                                               *
 *********************************************************************************************************************/
/**
  * @brief     This function is used to look for the prime.if the prime is finded,it will return 1, or return 0.
  * @param[in] n - the calue to judge.
  * @return    0 or 1
  */
static unsigned char uart_is_prime(unsigned int n);

/**
  *	@brief	This function serves to set pin for UART fuction.
  *	@param  tx_pin - To set TX pin.
  *	@param  rx_pin - To set RX pin.
  *	@return	none
  */
static void uart_set_fuc_pin(uart_tx_pin_e tx_pin, uart_rx_pin_e rx_pin);

/**********************************************************************************************************************
 *                                         global function implementation                                             *
 *********************************************************************************************************************/

/**
 * @brief      This function initializes the UART module.
 * @param[in]  uart_num    - UART0 or UART1.
 * @param[in]  div         - uart clock divider.
 * @param[in]  bwpc        - bitwidth, should be set to larger than 2.
 * @param[in]  parity      - selected parity type for UART interface.
 * @param[in]  stop_bit    - selected length of stop bit for UART interface.
 * @return     none
 * @note 	   sys_clk      baudrate   g_uart_div         g_bwpc
 *
 *  	       16Mhz        9600          118   			 13
 *                          19200         118     			  6
 *          	            115200          9       		 13
 *
 * 	           24Mhz        9600          249       		  9
 *           	 	    	19200		  124                 9
 *          	 	    	115200         12    			 15
 *
 *   	       32Mhz        9600          235       		 13
 *          	 	        19200		  235                 6
 *           	 	 	    115200         17    			 13
 *
 *   	       48Mhz        9600          499       		  9
 *          	 	 	    19200		  249                 9
 *           	 	 	    115200         25    			 15
*/
void uart_init(uart_num_e uart_num, unsigned short div, unsigned char bwpc, uart_parity_e parity,
               uart_stop_bit_e stop_bit)
{
    reg_uart_ctrl0(uart_num) &= ~(FLD_UART_BPWC_O);
    reg_uart_ctrl0(uart_num) |= bwpc;                          // set bwpc
    reg_uart_clk_div(uart_num) = (div | FLD_UART_CLK_DIV_EN);  // set div_clock

    // parity config
    if (parity) {
        reg_uart_ctrl1(uart_num) |= FLD_UART_PARITY_ENABLE;  // enable parity function
        if (UART_PARITY_EVEN == parity) {
            reg_uart_ctrl1(uart_num) &= (~FLD_UART_PARITY_POLARITY);  // enable even parity
        } else if (UART_PARITY_ODD == parity) {
            reg_uart_ctrl1(uart_num) |= FLD_UART_PARITY_POLARITY;  // enable odd parity
        }
    } else {
        reg_uart_ctrl1(uart_num) &= (~FLD_UART_PARITY_ENABLE);  // disable parity function
    }

    // stop bit config
    reg_uart_ctrl1(uart_num) &= (~FLD_UART_STOP_SEL);
    reg_uart_ctrl1(uart_num) |= stop_bit;
}

/***********************************************************
 * @brief  		This function serves to calculate the best bwpc(bit width) .i.e reg0x96.
 * @param[in]	baudrate - baut rate of UART.
 * @param[in]	pclk   - system clock.
 * @param[out]	div      - uart clock divider.
 * @param[out]	bwpc     - bitwidth, should be set to larger than 2.
 * @return 		none
 * @note        BaudRate*(div+1)*(bwpc+1) = system clock
 *  		    simplify the expression: div*bwpc =  constant(z)
 * 		        bwpc range from 3 to 15.so loop and get the minimum one decimal point
 */
void uart_cal_div_and_bwpc(unsigned int baudrate, unsigned int pclk, unsigned short *div, unsigned char *bwpc)
{
    unsigned char i = 0, j = 0;
    unsigned int primeInt = 0;
    unsigned char primeDec = 0;
    unsigned int D_intdec[13], D_int[13];
    unsigned char D_dec[13];

    primeInt = pclk / baudrate;
    primeDec = 10 * pclk / baudrate - 10 * primeInt;

    if (uart_is_prime(primeInt)) {  // primeInt is prime
        primeInt += 1;              // +1 must be not prime. and primeInt must be larger than 2.
    } else {
        if (primeDec > 5) {  // >5
            primeInt += 1;
            if (uart_is_prime(primeInt)) {
                primeInt -= 1;
            }
        }
    }

    for (i = 3; i <= 15; i++) {
        D_intdec[i - 3] = (10 * primeInt) / (i + 1);                   // get the LSB
        D_dec[i - 3] = D_intdec[i - 3] - 10 * (D_intdec[i - 3] / 10);  // get the decimal section
        D_int[i - 3] = D_intdec[i - 3] / 10;                           // get the integer section
    }

    // find the max and min one decimation point
    unsigned char position_min = 0, position_max = 0;
    unsigned int min = 0xffffffff, max = 0x00;
    for (j = 0; j < 13; j++) {
        if ((D_dec[j] <= min) && (D_int[j] != 0x01)) {
            min = D_dec[j];
            position_min = j;
        }
        if (D_dec[j] >= max) {
            max = D_dec[j];
            position_max = j;
        }
    }

    if ((D_dec[position_min] < 5) && (D_dec[position_max] >= 5)) {
        if (D_dec[position_min] < (10 - D_dec[position_max])) {
            *bwpc = position_min + 3;
            *div = D_int[position_min] - 1;
        } else {
            *bwpc = position_max + 3;
            *div = D_int[position_max];
        }
    } else if ((D_dec[position_min] < 5) && (D_dec[position_max] < 5)) {
        *bwpc = position_min + 3;
        *div = D_int[position_min] - 1;
    } else {
        *bwpc = position_max + 3;
        *div = D_int[position_max];
    }
}

/**
 * @brief  		This funtion serves to set r_rxtimeout. This setting is transfer one bytes need cycles base on uart_clk
 * 				For example, if  transfer one bytes (1start bit+8bits data+1 priority bit+2stop bits) total 12 bits,
 * 				this register setting should be (bpwc+1)*12.
 * @param[in]	uart_num - UART0 or UART1.
 * @param[in]	bwpc     - bitwidth, should be set to larger than 2.
 * @param[in]	bit_cnt  - bit number.
 * @param[in]	mul	     - mul.
 * @return 		none
 */
void uart_set_dma_rx_timeout(uart_num_e uart_num, unsigned char bwpc, unsigned char bit_cnt, uart_timeout_mul_e mul)
{
    reg_uart_rx_timeout0(uart_num) = (bwpc + 1) * bit_cnt;  // one byte includes 12 bits at most
    reg_uart_rx_timeout1(uart_num) &= (~FLD_UART_TIMEOUT_MUL);
    reg_uart_rx_timeout1(uart_num) |= mul;  // if over 2*(tmp_bwpc+1),one transaction end.
}

unsigned char uart_tx_byte_index[2] = {0};
/**
 * @brief     This function serves to send data by byte with not DMA method.
 * @param[in] uart_num - UART0 or UART1.
 * @param[in] tx_data  - the data to be send.
 * @return    none
 */
void uart_send_byte(uart_num_e uart_num, unsigned char tx_data)
{
    while (uart_get_txfifo_num(uart_num) > 7) {
    }

    reg_uart_data_buf(uart_num, uart_tx_byte_index[uart_num]) = tx_data;
    uart_tx_byte_index[uart_num]++;
    (uart_tx_byte_index[uart_num]) &= 0x03;
}

unsigned char uart_rx_byte_index[2] = {0};
/**
 * @brief     This function serves to receive uart data by byte with not DMA method.
 * @param[in] uart_num - UART0 or UART1.
 * @return    none
 */
unsigned char uart_read_byte(uart_num_e uart_num)
{
    unsigned char rx_data = reg_uart_data_buf(uart_num, uart_rx_byte_index[uart_num]);
    uart_rx_byte_index[uart_num]++;
    uart_rx_byte_index[uart_num] &= 0x03;
    return rx_data;
}

/**
 * @brief     This function serves to judge if the transmission of uart is done.
 * @param[in] uart_num - UART0 or UART1.
 * @return    return the tx status.
 * -          0:tx is done     1:tx isn't done
 */
unsigned char uart_tx_is_busy(uart_num_e uart_num)
{
    return ((reg_uart_status2(uart_num) & FLD_UART_TX_DONE) ? 0 : 1);
}

/**
 * @brief     This function serves to send uart0 data by halfword with not DMA method.
 * @param[in] uart_num - UART0 or UART1.
 * @param[in] data  - the data to be send.
 * @return    none
 */
void uart_send_hword(uart_num_e uart_num, unsigned short data)
{
    static unsigned char uart_tx_hword_index[2] = {0};

    while (uart_get_txfifo_num(uart_num) > 6) {
    }

    reg_uart_data_hword_buf(uart_num, uart_tx_hword_index[uart_num]) = data;
    uart_tx_hword_index[uart_num]++;
    uart_tx_hword_index[uart_num] &= 0x01;
}

/**
 * @brief     This function serves to send data by word with not DMA method.
 * @param[in] uart_num - UART0 or UART1.
 * @param[in] data - the data to be send.
 * @return    none
 */
void uart_send_word(uart_num_e uart_num, unsigned int data)
{
    while (uart_get_txfifo_num(uart_num) > 4) {
    }

    reg_uart_data_word_buf(uart_num) = data;
}

/**
 * @brief     This function serves to set the RTS pin's level manually.
 * @param[in] uart_num - UART0 or UART1.
 * @param[in] polarity - set the output of RTS pin(only for manual mode).
 * @return    none
 */
void uart_set_rts_level(uart_num_e uart_num, unsigned char polarity)
{
    if (polarity) {
        reg_uart_ctrl2(uart_num) |= FLD_UART_RTS_MANUAL_V;
    } else {
        reg_uart_ctrl2(uart_num) &= (~FLD_UART_RTS_MANUAL_V);
    }
}

/**
 *	@brief		This function serves to set pin for UART0 cts function .
 *	@param[in]  cts_pin -To set cts pin.
 *	@return		none
 */
void uart_set_cts_pin(uart_cts_pin_e cts_pin)
{
    unsigned char val = 0;
    unsigned char mask = 0xff;
    if (cts_pin == UART0_CTS_PA1) {
        mask = (unsigned char)~(BIT(2) | BIT(3));
        val = BIT(2);
    } else if (cts_pin == UART0_CTS_PB6) {
        mask = (unsigned char)~(BIT(4) | BIT(5));
        val = BIT(5);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (cts_pin == UART0_CTS_PD0) {
        mask = (unsigned char)~(BIT(0) | BIT(1));
        val = 0;
    } else if (cts_pin == UART1_CTS_PC4) {
        mask = (unsigned char)~(BIT(0) | BIT(1));
        val = BIT(1);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (cts_pin == UART1_CTS_PD4) {
        mask = (unsigned char)~(BIT(0) | BIT(1));
        val = 0;
    } else if (cts_pin == UART1_CTS_PE1) {
        mask = (unsigned char)~(BIT(2) | BIT(3));
        val = BIT(2);
    }
    reg_gpio_func_mux(cts_pin) = (reg_gpio_func_mux(cts_pin) & mask) | val;
    gpio_function_dis(cts_pin);
}

/**
 *	@brief		This function serves to set pin for UART0 rts function .
 *	@param[in]  rts_pin - To set rts pin.
 *	@return		none
 */
void uart_set_rts_pin(uart_rts_pin_e rts_pin)
{
    unsigned char val = 0;
    unsigned char mask = 0xff;
    if (rts_pin == UART0_RTS_PA2) {
        mask = (unsigned char)~(BIT(4) | BIT(5));
        val = BIT(4);
    } else if (rts_pin == UART0_RTS_PB4) {
        mask = (unsigned char)~(BIT(0) | BIT(1));
        val = BIT(1);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rts_pin == UART0_RTS_PD1) {
        mask = (unsigned char)~(BIT(2) | BIT(3));
        val = 0;
    } else if (rts_pin == UART1_RTS_PC5) {
        mask = (unsigned char)~(BIT(2) | BIT(3));
        val = BIT(3);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rts_pin == UART1_RTS_PD5) {
        mask = (unsigned char)~(BIT(2) | BIT(3));
        val = 0;
    } else if (rts_pin == UART1_RTS_PE3) {
        mask = (unsigned char)~(BIT(6) | BIT(7));
        val = BIT(6);
    }
    reg_gpio_func_mux(rts_pin) = (reg_gpio_func_mux(rts_pin) & mask) | val;
    gpio_function_dis(rts_pin);
}

/**
* @brief      This function serves to select pin for UART module.
* @param[in]  tx_pin  - the pin to send data.
* @param[in]  rx_pin  - the pin to receive data.
* @return     none
*/
void uart_set_pin(uart_tx_pin_e tx_pin, uart_rx_pin_e rx_pin)
{
    gpio_set_up_down_res(tx_pin, GPIO_PIN_PULLUP_10K);
    gpio_set_up_down_res(rx_pin, GPIO_PIN_PULLUP_10K);
    uart_set_fuc_pin(tx_pin, rx_pin);  // set tx and rx pin
    gpio_input_en(tx_pin);
    gpio_input_en(rx_pin);
}

/**
* @brief      This function serves to set rtx pin for UART module.
* @param[in]  rx_pin  - the rtx pin need to set.
* @return     none
*/
void uart_set_rtx_pin(uart_rx_pin_e rx_pin)
{
    unsigned char val = 0;
    unsigned char mask = 0xff;
    gpio_set_up_down_res(rx_pin, GPIO_PIN_PULLUP_10K);
    if (rx_pin == UART0_RX_PA4) {
        mask = (unsigned char)~(BIT(1) | BIT(0));
        val = BIT(0);
    } else if (rx_pin == UART0_RX_PB3) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = BIT(7);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rx_pin == UART0_RX_PD3) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = 0;
    } else if (rx_pin == UART1_RX_PC7) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = BIT(7);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rx_pin == UART1_RX_PD7) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = 0;
    } else if (rx_pin == UART1_RX_PE2) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = BIT(4);
    }
    reg_gpio_func_mux(rx_pin) = (reg_gpio_func_mux(rx_pin) & mask) | val;
    gpio_input_en(rx_pin);
    gpio_function_dis(rx_pin);
}

/**
* @brief     This function serves to send data with not DMA method.
* @param[in] uart_num - UART0 or UART1.
* @param[in] addr     - pointer to the buffer containing data need to send.
* @param[in] len      - NDMA transmission length.
* @return    1
*/
unsigned char uart_send(uart_num_e uart_num, unsigned char *addr, unsigned char len)
{
    for (unsigned char i = 0; i < len; i++) {
        uart_send_byte(uart_num, addr[i]);
    }
    return 1;
}

/**
 * @brief     	This function serves to send data by DMA, this function tell the DMA to get data from the RAM and start
 * @param[in]  	uart_num - UART0 or UART1.
 * @param[in] 	addr     - pointer to the buffer containing data need to send.
 * @param[in] 	len      - DMA transmission length.The maximum transmission length of DMA is 0xFFFFFC bytes,
 *                         so dont'n over this length.
 * @return      1  dma start send.
 *              0  the length is error.
 */
unsigned char uart_send_dma(uart_num_e uart_num, unsigned char *addr, unsigned int len)
{
    if (len != 0) {
        uart_clr_tx_done(uart_num);
        dma_set_address(uart_dma_tx_chn[uart_num], (unsigned int)convert_ram_addr_cpu2bus(addr),
                        reg_uart_data_buf_adr(uart_num));
        dma_set_size(uart_dma_tx_chn[uart_num], len, DMA_WORD_WIDTH);
        dma_chn_en(uart_dma_tx_chn[uart_num]);
        return 1;
    } else {
        return 0;
    }
}

/**
 * @brief     	This function serves to receive data function by DMA,
 *              this  function tell the DMA to get data from the uart data fifo.
 * @param[in]  	uart_num - UART0 or UART1.
 * @param[in] 	addr     - pointer to the buffer  receive data.
 * @param[in]   rev_size - the receive length of DMA,The maximum transmission length of DMA is 0xFFFFFC bytes,
 *                         so dont'n over this length.
 * @note        The DMA version of A0 has some limitians.
 *              0:We should know the real receive length-len.
 *              1:If the data length we receive isn't the multiple of 4(the DMA carry 4-byte one time),like 5,
 *              it will carry 8 byte, while the last 3-byte data is random.
 *              2:The receive buff length sholud be equal to rec_size.
 *              The relation of the receive buff length and rec_size and the real receive data length-len:
 *              REC_BUFF_LEN=rec_size= ((len%4)==0 ? len : ((len/4)+1)*4).
 *              The DMA version of A1 can receive any length of data,the rev_size is useless.
 * @return    	none
 */
void uart_receive_dma(uart_num_e uart_num, unsigned char *addr, unsigned int rev_size)
{
    dma_chn_dis(uart_dma_rx_chn[uart_num]);
    /* In order to be able to receive data of unknown length(A0 doesn't suppport),
     * the DMA SIZE is set to the longest value 0xffffffff. After entering suspend and wake up,
     * and then continue to receive, DMA will no longer move data from uart fifo,
     * because DMA thinks that the last transmission was not completed and must disable dma_chn first.
     * Modified by minghai,confirmed qiangkai 2020.11.26.
     */
    dma_set_address(uart_dma_rx_chn[uart_num], reg_uart_data_buf_adr(uart_num),
                    (unsigned int)convert_ram_addr_cpu2bus(addr));
    if (g_chip_version == 0xff) {
        dma_set_size(uart_dma_rx_chn[uart_num], rev_size, DMA_WORD_WIDTH);
    } else {
        reg_dma_size(uart_dma_rx_chn[uart_num]) = 0xffffffff;
    }

    dma_chn_en(uart_dma_rx_chn[uart_num]);
}

/**
  * @brief     This function serves to set uart tx_dam channel and config dma tx default.
  * @param[in] uart_num - UART0 or UART1.
  * @param[in] chn      - dma channel.
  * @return    none
  */
void uart_set_tx_dma_config(uart_num_e uart_num, dma_chn_e chn)
{
    uart_dma_tx_chn[uart_num] = chn;
    dma_config(chn, &uart_tx_dma_config[uart_num]);
}

/**
  * @brief     This function serves to set uart rx_dam channel and config dma rx default.
  * @param[in] uart_num - UART0 or UART1.
  * @param[in] chn      - dma channel.
  * @return    none
  */
void uart_set_rx_dma_config(uart_num_e uart_num, dma_chn_e chn)
{
    uart_dma_rx_chn[uart_num] = chn;
    dma_config(chn, &uart_rx_dma_config[uart_num]);
}

/**
  * @brief     UART hardware flow control configuration. Configure CTS.
  * @param[in] uart_num   - UART0 or UART1.
  * @param[in] cts_pin    - RTS pin select.
  * @param[in] cts_parity - when CTS's input equals to select, tx will be stopped.
  * @return    none
  */
void uart_cts_config(uart_num_e uart_num, uart_cts_pin_e cts_pin, unsigned char cts_parity)
{
    uart_set_cts_pin(cts_pin);

    gpio_input_en(cts_pin);  // enable input

    if (cts_parity) {
        reg_uart_ctrl1(uart_num) |= FLD_UART_TX_CTS_POLARITY;
    } else {
        reg_uart_ctrl1(uart_num) &= (~FLD_UART_TX_CTS_POLARITY);
    }
}

/**
  * @brief     UART hardware flow control configuration. Configure RTS.
  * @param[in] uart_num     - UART0 or UART1.
  * @param[in] rts_pin      - RTS pin select.
  * @param[in] rts_parity   - whether invert the output of RTS pin(only for auto mode)
  * @param[in] auto_mode_en - set the mode of RTS(auto or manual).
  * @return    none
  */
void uart_rts_config(uart_num_e uart_num, uart_rts_pin_e rts_pin, unsigned char rts_parity, unsigned char auto_mode_en)
{
    uart_set_rts_pin(rts_pin);

    if (auto_mode_en) {
        reg_uart_ctrl2(uart_num) |= FLD_UART_RTS_MANUAL_M;
    } else {
        reg_uart_ctrl2(uart_num) &= (~FLD_UART_RTS_MANUAL_M);
    }

    if (rts_parity) {
        reg_uart_ctrl2(uart_num) |= FLD_UART_RTS_POLARITY;
    } else {
        reg_uart_ctrl2(uart_num) &= (~FLD_UART_RTS_POLARITY);
    }
}

/**********************************************************************************************************************
  *                    						local function implementation                                             *
  *********************************************************************************************************************/
/**
   * @brief     This function is used to look for the prime.if the prime is finded,it will return 1, or return 0.
   * @param[in] n - the calue to judge.
   * @return    0 or 1
   */
static unsigned char uart_is_prime(unsigned int n)
{
    unsigned int i = 5;
    if (n <= 3) {
        return 1;  // althought n is prime, the bwpc must be larger than 2.
    } else if ((n % 2 == 0) || (n % 3 == 0)) {
        return 0;
    } else {
        for (i = 5; i * i < n; i += 6) {
            if ((n % i == 0) || (n % (i + 2)) == 0) {
                return 0;
            }
        }
        return 1;
    }
}

/**
  *	@brief	This function serves to set pin for UART fuction.
  *	@param  tx_pin - To set TX pin.
  *	@param  rx_pin - To set RX pin.
  *	@return	none
  */
static void uart_set_fuc_pin(uart_tx_pin_e tx_pin, uart_rx_pin_e rx_pin)
{
    unsigned char val = 0;
    unsigned char mask = 0xff;

    if (tx_pin == UART0_TX_PA3) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = BIT(6);
    } else if (tx_pin == UART0_TX_PB2) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = BIT(5);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (tx_pin == UART0_TX_PD2) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = 0;
    } else if (tx_pin == UART1_TX_PC6) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = BIT(5);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (tx_pin == UART1_TX_PD6) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = 0;
    } else if (tx_pin == UART1_TX_PE0) {
        mask = (unsigned char)~(BIT(1) | BIT(0));
        ;
        val = BIT(0);
    }
    reg_gpio_func_mux(tx_pin) = (reg_gpio_func_mux(tx_pin) & mask) | val;

    if (rx_pin == UART0_RX_PA4) {
        mask = (unsigned char)~(BIT(1) | BIT(0));
        val = BIT(0);
    } else if (rx_pin == UART0_RX_PB3) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = BIT(7);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rx_pin == UART0_RX_PD3) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = 0;
    } else if (rx_pin == UART1_RX_PC7) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = BIT(7);
        reg_gpio_pad_mul_sel |= BIT(0);
    } else if (rx_pin == UART1_RX_PD7) {
        mask = (unsigned char)~(BIT(7) | BIT(6));
        val = 0;
    } else if (rx_pin == UART1_RX_PE2) {
        mask = (unsigned char)~(BIT(5) | BIT(4));
        val = BIT(4);
    }
    // note: setting pad the function must before setting no_gpio function,
    // cause it will lead to uart transmit extra one byte data at begin.(confirmed by minghai&sunpeng)
    reg_gpio_func_mux(rx_pin) = (reg_gpio_func_mux(rx_pin) & mask) | val;

    gpio_function_dis(tx_pin);
    gpio_function_dis(rx_pin);
}
